﻿using Engine;
using System;
using System.Collections.Generic;

namespace Game
{
    /// <summary>
    /// 立方区域
    /// </summary>
    public class CubeArea
    {
        public Point3 MaxPoint;
        public Point3 MinPoint;
        public Point3 Current;
        public Point3 Center;
        public int LengthX;
        public int LengthY;
        public int LengthZ;
        public bool IsPoint;

        public CubeArea(Point3 point1, Point3 point2)
        {
            MaxPoint = new Point3(MathUtils.Max(point1.X, point2.X), MathUtils.Max(point1.Y, point2.Y), MathUtils.Max(point1.Z, point2.Z));
            MinPoint = new Point3(MathUtils.Min(point1.X, point2.X), MathUtils.Min(point1.Y, point2.Y), MathUtils.Min(point1.Z, point2.Z));
            Current = MinPoint;
            LengthX = MathUtils.Abs(point1.X - point2.X) + 1;
            LengthY = MathUtils.Abs(point1.Y - point2.Y) + 1;
            LengthZ = MathUtils.Abs(point1.Z - point2.Z) + 1;
            Center = MinPoint + new Point3((int)(LengthX / 2f), (int)(LengthY / 2f), (int)(LengthZ / 2f));
            IsPoint = (LengthX == 1 && LengthY == 1 && LengthZ == 1);
        }

        public bool Ergodic(Func<bool> action)
        {
            for (int x = 0; x < LengthX; x++)
            {
                for (int y = 0; y < LengthY; y++)
                {
                    for (int z = 0; z < LengthZ; z++)
                    {
                        Current = new Point3(x + MinPoint.X, y + MinPoint.Y, z + MinPoint.Z);
                        bool result = action.Invoke();
                        if (result) return true;
                    }
                }
            }
            return false;
        }

        public void Ergodic(int division, float time, Action<Point3, Point3, Point3> action)
        {
            int chunkXL = (int)(LengthX / division) + 1;
            int chunkYL = (int)(LengthY / division) + 1;
            int chunkZL = (int)(LengthZ / division) + 1;
            float t = 0f;
            List<Point3> points = new List<Point3>();
            int p = 0;
            for (int ci = 0; ci < chunkXL; ci++)
            {
                for (int cj = 0; cj < chunkYL; cj++)
                {
                    for (int ck = 0; ck < chunkZL; ck++)
                    {
                        points.Add(new Point3(ci, cj, ck));
                        Time.QueueTimeDelayedExecution(Time.RealTime + t, delegate
                        {
                            int ox = MinPoint.X + points[p].X * division;
                            int oy = MinPoint.Y + points[p].Y * division;
                            int oz = MinPoint.Z + points[p].Z * division;
                            action.Invoke(new Point3(ox, oy, oz), points[p], points[points.Count - 1]);
                            p++;
                        });
                        t += time;
                    }
                }
            }
        }

        public void ErgodicByChunk(float perpareTime, float intervalTime, Action<Point3, Point2, Point2> action)
        {
            int chunkXL = (int)(LengthX / 16) + 1;
            int chunkZL = (int)(LengthZ / 16) + 1;
            action.Invoke(MinPoint, new Point2(-1, -1), new Point2(-1, -1));
            float time = perpareTime;
            int p = 0;
            List<Point2> points = new List<Point2>();
            for (int ci = 0; ci < chunkXL; ci++)
            {
                for (int cj = 0; cj < chunkZL; cj++)
                {
                    points.Add(new Point2(ci, cj));
                    Time.QueueTimeDelayedExecution(Time.RealTime + time, delegate
                    {
                        int ox = MinPoint.X + points[p].X * 16;
                        int oy = MinPoint.Y;
                        int oz = MinPoint.Z + points[p].Y * 16;
                        action.Invoke(new Point3(ox, oy, oz), points[p], points[points.Count - 1]);
                        p++;
                    });
                    time += intervalTime;
                }
            }
        }

        public bool Exist(Vector3 target)
        {
            bool pass1 = (target.X >= MinPoint.X && target.Y >= MinPoint.Y && target.Z >= MinPoint.Z);
            bool pass2 = (target.X <= MaxPoint.X + 1 && target.Y <= MaxPoint.Y + 1 && target.Z <= MaxPoint.Z + 1);
            return pass1 && pass2;
        }

        public bool Exist(Point3 target)
        {
            bool pass1 = (target.X >= MinPoint.X && target.Y >= MinPoint.Y && target.Z >= MinPoint.Z);
            bool pass2 = (target.X <= MaxPoint.X && target.Y <= MaxPoint.Y && target.Z <= MaxPoint.Z);
            return pass1 && pass2;
        }
    }
}